#include <shlobj.h>
#include <stdio.h>

#include "../tdp2/tdp2_threading.hpp"

using namespace TDP;

extern "C"
{
#include "progress.h"
}

#define PROGRESS_SIMPLE

#ifdef PROGRESS_SIMPLE

static RDX::Threading::LightMutex progMutex;

static int progMaximum = 100;
static int oldf = 0;


extern "C" void Progress_Init(void)
{
}

extern "C" void Progress_SetLoad(int maxLoad)
{
	progMaximum = maxLoad;

	oldf = -1;
}

extern "C" int Progress_SetProgress(int progress)
{
	static const char pacifierStr[] = "0...1...2...3...4...5...6...7...8...9...\n ";
	__int64 f;

	progMutex.Acquire();

	if(progMaximum > 1)
	{
		f = (__int64)40*(__int64)progress / (__int64)(progMaximum-1);
		while(oldf < f)
		{
			oldf++;
			fputc(pacifierStr[oldf], stdout);
		}
	}

	progMutex.Release();

	return 1;
}

extern "C" void Progress_SetMessage(const char *msg)
{
	printf("%s\n", msg);
}
#endif

#ifdef PROGRESS_IPD
static IProgressDialog *dlg = NULL;
static int progMaximum = 100;
static terVector<wchar_t> umessage;

static __int64 oldf;
static __int64 oldpct;

static wchar_t *TempUnicodeMessage(const char *msg)
{
	size_t len;

	len = strlen(msg) + 1;
	umessage.Alloc(len);

	wchar_t *uout = umessage;
	while(len--)
		*uout++ = *msg++;

	return umessage;
}

extern "C" void Progress_Init(void)
{
	CoInitialize(NULL);

	CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER, IID_IProgressDialog, (void **)&dlg);

	if(dlg)
	{
		dlg->StartProgressDialog(NULL, NULL, PROGDLG_NORMAL | PROGDLG_NOTIME, NULL);
		dlg->SetTitle(L"Update Progress");
		dlg->SetCancelMsg(L"Cancelling...", NULL);
		dlg->SetProgress(1, 100);
		Sleep(500);
	}
}

extern "C" void Progress_SetLoad(int maxLoad)
{
	progMaximum = maxLoad;
	if(dlg)
	{
		dlg->SetProgress(0, 100);
	}

	oldf = -1;
	oldpct = -1;
}

extern "C" int Progress_SetProgress(int progress)
{
	static const char pacifierStr[] = "0...1...2...3...4...5...6...7...8...9...  ";
	__int64 f;

	if(dlg)
	{
		if(dlg->HasUserCancelled())
			return 0;
	}


	if(progMaximum > 1)
	{
		f = (__int64)100*(__int64)progress / (__int64)(progMaximum-1);
		if(f != oldpct)
		{

			char tempMessage[256];
			sprintf(tempMessage, "%i%% completed", (int)f);
			if(dlg)
			{
				Sleep(10);
				dlg->SetProgress((int)f, 100);
				dlg->SetLine(2, TempUnicodeMessage(tempMessage), FALSE, NULL);
			}
			oldpct = f;
		}
	}

	return 1;
}

extern "C" void Progress_SetMessage(const char *msg)
{
	if(dlg)
	{
		dlg->SetLine(1, TempUnicodeMessage(msg), FALSE, NULL);
	}
}

#endif

#ifdef PROGRESS_PIPE

static int progMaximum = 100;
static terVector<wchar_t> umessage;

static __int64 oldf;
static __int64 oldpct;

extern "C" void Progress_Init(void)
{
}

extern "C" void Progress_SetLoad(int maxLoad)
{
	progMaximum = maxLoad;
	oldf = -1;
	oldpct = -1;
}

static void ToPayloadCode(__int64 v, unsigned char *p)
{
	p[0] = (unsigned char)(v);
	p[1] = (unsigned char)(v >> 8);
	p[2] = (unsigned char)(v >> 16);
	p[3] = (unsigned char)(v >> 24);
}

static void ToPayloadCode(int v, unsigned char *p)
{
	p[0] = (unsigned char)(v);
	p[1] = (unsigned char)(v >> 8);
	p[2] = (unsigned char)(v >> 16);
	p[3] = (unsigned char)(v >> 24);
}

extern "C" int Progress_SetProgress(int progress)
{
	static const char pacifierStr[] = "0...1...2...3...4...5...6...7...8...9...  ";
	__int64 f;

	if(progress == progMaximum-1)
		f = 39;
	else
		f = 39*progress / (progMaximum-1);

	/*
	while (oldf < f)
	{
		oldf++;
		printf ("%c", pacifierStr[oldf]);
	}
	*/

	if(progMaximum > 1)
	{
		f = ((__int64)100)*((__int64)progress) / (((__int64)progMaximum)-1);
		if(f > 100)
			f = 100;
		if(f != oldpct)
		{
			unsigned char payload[4];
			ToPayloadCode(f, payload);
			terCWrite(TDP_PIPECODE_CHANGEPERCENTAGE, payload, 4);
			oldpct = f;
		}
	}

	return 1;
}

extern "C" void Progress_SetMessage(const char *msg)
{
	terCWrite(TDP_PIPECODE_NEWOPERATION, msg, strlen(msg));
}

#endif

